package org.facyt.commons.view.window;

import java.util.List;
import java.util.Map;

import org.facyt.commons.view.bean.AbstractBeanForm;
import org.facyt.commons.view.form.GenericForm;

import com.vaadin.data.util.BeanItem;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;

public abstract class FormWindow <T extends AbstractBeanForm> extends GenericWindow{

	
	protected GenericForm<T> form;

	protected Button botonAceptar;
	protected Button botonCancelar;

	
	@Override
	protected void agregarPanel() {
		VerticalLayout layout = crearLayout();
		agregarFormulario(layout);
		agregarBotones(layout);
		
	}
	
	protected void doSetItemForm(T itemForm) {

		if (itemForm == null) {
			itemForm = crearBeanForm();
		}
		form.setItemDataSource(new BeanItem<T>(itemForm), obtenerOrdenPropiedades());
		
	}
	
	/**
	 * Crea el panel que contiene el formulario y los botones
	 * 
	 * @return
	 */
	protected VerticalLayout crearLayout() {
		VerticalLayout layout = new VerticalLayout();
		addComponent(layout);
		return layout;
	}
	
	
	/**
	 * Agrega el formulario
	 * 
	 * @param layout
	 */
	protected void agregarFormulario(VerticalLayout layout) {

		form = new GenericForm<T>(crearBeanForm());
		
		// se agregan los campos no comunes
		addFieldGenerator(form);

		// se obtienen el ordenamiento de las propiedades
		form.setOrderedPropertiesIds(obtenerOrdenPropiedades());

		// se agregan los label a los componentes
		form.addFielCaption(obtenerCaptionForm());

		// se obtienen los campos requeridos
		form.setRequieredField(obtenerCamposRequeridos());

		// se obtienen los campos solo lectura
		form.setReadOnlyField(obtenerCamposSoloLectura());
		
		form.setValidationVisible(false);
		
		// se agrega la visibilidad
		Object[] visibilidad = obtenerVisibilidadComponentesFormulario();

		if (visibilidad != null)
			form.setVisibleItemProperties(visibilidad);

		doSetItemForm(null);
		
		layout.addComponent(form);
	}
	
	/**
	 * Agrega los botones
	 * 
	 * @param layout
	 */
	protected void agregarBotones(VerticalLayout layout) {
		HorizontalLayout horizontalLayout = new HorizontalLayout();
		if (isBotonAceptarVisible()) {
			botonAceptar = new Button();
			botonAceptar.addStyleName("boton-facyt");
			botonAceptar.setCaption(obtenerNombreBotonAceptar());
			botonAceptar.addListener(new Button.ClickListener() {

				@Override
				public void buttonClick(ClickEvent event) {
					if (isValidoFormulario()) {
						form.commit();
						aceptar();
					}

				}

			});

			horizontalLayout.addComponent(botonAceptar);
			horizontalLayout.setComponentAlignment(botonAceptar,
					Alignment.MIDDLE_RIGHT);
			
		}

		if (isBotonCancelarVisible()) {
			botonCancelar = new Button();
			botonCancelar.setCaption(obtenerNombreBotonCancelar());
			botonCancelar.addStyleName("boton-facyt");
			botonCancelar.addListener(new Button.ClickListener() {
				@Override
				public void buttonClick(ClickEvent event) {
					form.discard();
					form.setComponentError(null);
					botonAceptar.setComponentError(null);
					cancelar();
				}
			});
			horizontalLayout.addComponent(botonCancelar);
			horizontalLayout.setComponentAlignment(botonCancelar,
					Alignment.MIDDLE_RIGHT);
		}
		
		
		horizontalLayout.setSpacing(true);

		layout.addComponent(horizontalLayout);
		layout.setComponentAlignment(horizontalLayout, Alignment.BOTTOM_RIGHT);
	}
	
	/**
	 * Crea el bean para el form
	 * 
	 * @return
	 */
	protected abstract T crearBeanForm();
	
	/**
	 * Obtiene los label de los caption
	 * 
	 * @return
	 */
	protected abstract Map<String, String> obtenerCaptionForm();

	/**
	 * Agrega los componentes que el generador por default no detecta
	 * 
	 * @param form
	 *            Representa el formulario
	 */
	protected abstract void addFieldGenerator(GenericForm<T> form);

	/**
	 * Obtiene la visibilidad de los componentes del formulario
	 * 
	 * @return retorna la visibilidad de los componentes
	 */
	protected abstract Object[] obtenerVisibilidadComponentesFormulario();

	/**
	 * Obtiene el orden de las propiedades, para poder mostrar en el orden que
	 * uno desea el formulario
	 * 
	 * @return
	 */
	protected abstract List<String> obtenerOrdenPropiedades();

	/**
	 * Obtiene los campos solo lectura
	 * 
	 * @return
	 */
	protected abstract Map<String, Boolean> obtenerCamposSoloLectura();

	/**
	 * Obtiene los campos requeridos
	 * 
	 * @return
	 */
	protected abstract Map<String, Boolean> obtenerCamposRequeridos();

	/**
	 * Obtiene el nombre del boton aceptar
	 * 
	 * @return
	 */
	protected abstract String obtenerNombreBotonAceptar();

	/**
	 * Obtiene el nombre del boton cancelar
	 * 
	 * @return
	 */
	protected abstract String obtenerNombreBotonCancelar();

	/**
	 * Desde este metodo se puede llamar al servicio
	 */
	protected abstract void aceptar();

	/**
	 * Valida si el formulario es correcto.
	 * 
	 * @return
	 */
	protected abstract boolean isValidoFormulario();

	/**
	 * Realiza la accion cancelar
	 */
	protected abstract void cancelar();

	/**
	 * Verifica si el boton aceptar es visible
	 * @return
	 */
	protected abstract boolean isBotonAceptarVisible();

	/**
	 * Verifica si el boton cancelar es visible
	 * @return
	 */
	protected abstract boolean isBotonCancelarVisible();

}
